前面文章有介紹到Delay的用法,Delay雖然也可以做到延遲或控制時間的效果,但嚴格來說透過Delay去做控制並不準確,這時候就可以用到Timer來做時間上的控制!
STM32L476RG中一共有11個計時器,其中又分為基本、通用、高階三種計時器。
基本定時器大多用來作為基本的定時功能,較常用的是通用定時器除了基本定時功能外,可以做輸入捕捉、輸出比較等等用途,而高級定時器可以對於馬達做死區控制的互補信號輸出等等功能。
這篇主要介紹定時器的基本使用方法,先解釋DataSheet當中的幾項:
以STM32L476RG來說當中11種定時器分別來自不同的匯流排(APB1與APB2),其中TIM2,3,4,5,6,7來自APB1,而TIM1,8,15,16,17則來自APB2,在對於預分頻係數做設定的時候要注意一下。
在IDE當中的.ioc檔中點選上方的Clock Configuration,可以去對Prescaler(預分頻係數)做設定。
分為兩個匯流排去做設定,當中有1,2,4,8,16可以依照需求做選擇。舉例來說如果下方預分頻係數選擇16,則分頻後會變成1Mhz。(如果從這邊去做設定的話會影響到所有連接在該匯流排的時脈)
在使用時大多會從左側選單當中的Timer去做Prescaler的設定,這邊先選擇通用定時器Timer2去做設置。
ARR : 自動裝載值(上方的Counter Period)
PSC : 預分頻係數
Tclk : APB時鐘,通常會等於系統時鐘
舉例:
假設TCLK = 80M , PSC = 7999 , ARR = 9999
⇒ (9999+1)*(7999+1) / 80000000hz = 1s
1Mhz = 1000khz =1000000hz
1Mhz = 1us 1khz = 1ms 1hz = 1s
那這樣定時器就是設定為1秒(計數週期從0數到9999需要1秒的時間)
在stm32xxxx_hal_tim當中可以找到相關的定時器函數
HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)
{
..........
}
//用法 htimx -> x 看是哪個TIM就填哪個
HAL_TIM_Base_Start(&htim2);
HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim)
{
..........
}
//用法 htimx -> x 看是哪個TIM就填哪個
HAL_TIM_Base_Stop(&htim2);
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
{
...........
}
//用法 htimx -> x 看是哪個TIM就填哪個
HAL_TIM_Base_Start_IT(&htim2);
HAL_StatusTypeDef HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim);
{
...........
}
//用法 htimx -> x 看是哪個TIM就填哪個
HAL_TIM_Base_Stop_IT(&htim2);
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
}
//用法 htimx -> x 看是哪個TIM就填哪個
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == htim2.Instance) //假如tim實例等於tim2才進迴圈
{
.....................
}
}
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
/* USER CODE END 2 */
接著找到下方的/* USER CODE BEGIN 4 / / USER CODE END 4 */,在當中寫入中斷回調函數,同樣的記得宣告全域變數i。
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim){
if(htim->Instance == htim2.Instance){
i++;
if(i==3)
{
i = 0;
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}
}
}
/* USER CODE END 4 */
在這邊因為前面設定溢出時間為1秒,可以知道的是他觸發一次時間中斷是1秒一次,而i實際上也就是秒數的變化!接下來利用前面提到的Toggle函數可以達到每3秒切換一次燈號,可以看看板載上的LED燈是否有按照設定的時間去做變化!
前面介紹過有關Timer的使用方式,但使用的是中斷方式。結合其他中斷時需要考慮到優先權的問題,那如何利用定時器達到延時效果而不進入中斷呢?下方介紹如何去做設定。
__HAL_TIM_GET_COUNTER(&htimx); //x填入對應的TIM
這時我們就可以利用CNT的數值來做到延時效果,首先先啟動定時器。
HAL_TIM_Base_Start(&htim3);
接著可以在while(1)當中寫入下方程式碼,記得宣告timerct變數。
剛剛已知定時器為兩秒也就是說從0數至1999需要兩秒,那這時將當前的計數值減去後續的計數值大於1000時即為一秒。因為16Mhz/(15999+1) = 1khz,而1khz=1ms 接著 *1000 = 1s,可以看一下板載LED有沒有每一秒切換一次。
if (__HAL_TIM_GET_COUNTER(&htim3) - timerct >= 1000)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
timerct = __HAL_TIM_GET_COUNTER(&htim3);
}
以上內容如果有誤的話,麻煩各位通知我。感謝~